package com.example.utils;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.example.entity.dto.WechatReturnObjectDTO;
import com.example.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @description: 微信小程序工具类
 * @author: zeran
 * @date: 2024/12/25 15:57
 */
@Component
@Slf4j
public class WechatUtil {
	//	读取application.yml的内容,配置自己的app_id、app_secret
	@Value("${com.wx.app-id}")
	private String APP_ID;
	@Value("${com.wx.app-secret}")
	private String APP_SECRET;

	/**
	 * 获取微信小程序的openid
	 *
	 * @param loginCode 微信小程序登录返回的code
	 * @return WechatReturnObjectDTO
	 */
	public WechatReturnObjectDTO validLoginCodeFromWechat(String loginCode) {
		String url = "https://api.weixin.qq.com/sns/jscode2session";
		String requestUrl = UriComponentsBuilder.fromHttpUrl(url)
				.queryParam("appid", APP_ID)
				.queryParam("secret", APP_SECRET)
				.queryParam("js_code", loginCode)
				.queryParam("grant_type", "authorization_code")
				.toUriString();

		HttpResponse response;
		try {
			response = HttpUtil.createGet(requestUrl).execute();
		} catch (Exception e) {
			throw new ServiceException("请求微信服务器异常");
		}
		// 返回WechatReturnObjectDTO
		WechatReturnObjectDTO wechatReturnObjectDTO = JSONUtil.toBean(response.body(), WechatReturnObjectDTO.class);
		// 根据错误码映射到对应的异常信息
		Map<Integer, String> errorMessages = Map.of(
				40029, "code 无效",
				45011, "API 调用太频繁，请稍候再试",
				40226, "高风险等级用户，小程序登录拦截",
				-1, "系统繁忙，此时请开发者稍候再试"
		);
		// 检查是否存在错误码并抛出对应异常
		if (errorMessages.containsKey(wechatReturnObjectDTO.getErrcode())) {
			throw new ServiceException(errorMessages.get(wechatReturnObjectDTO.getErrcode()));
		}
		if (ObjectUtil.isNull(wechatReturnObjectDTO) || ObjectUtil.isNull(wechatReturnObjectDTO.getOpenid())) {
			throw new ServiceException("请求微信服务器返回为null");
		}

		return wechatReturnObjectDTO;
	}

	/**
	 * 生成带参数的小程序码
	 *
	 * @param id id
	 * @return 二维码字节流
	 */
	public byte[] generateWechatQRCode(String id) {
		// 1. 获取 access_token
		String requestToAccessTokenURL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential"
				+ "&appid=" + APP_ID
				+ "&secret=" + APP_SECRET;
		String responseFromGetAccessToken = HttpUtil.get(requestToAccessTokenURL);
		String accessToken = new JSONObject(responseFromGetAccessToken).getStr("access_token");

		// 2. 请求生成小程序码
		Map<String, Object> params = new HashMap<>();
		params.put("scene", "shop_id=" + id); // 设置 scene 参数
		params.put("page", "pages/user_submit_evaluation/user_submit_evaluation"); // 设置跳转页面路径
		params.put("check_path", false); // 检查page 是否存在（必须已发布的小程序）
		params.put("env_version", "develop");
		params.put("width", 430); // 设置二维码宽度
		params.put("auto_color", true); // 自动配置颜色

		// 3. 请求微信服务器获取二维码
		String requestToQRCodeURL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken;

		// 返回二维码字节流
		HttpResponse responseFromGetQRCode =
				HttpUtil.createPost(requestToQRCodeURL)
						.body(new JSONObject(params).toString())
						.header("Content-Type", "application/json") // 必须设置 Content-Type
						.execute();

		byte[] buffer = responseFromGetQRCode.bodyBytes();
		if (responseFromGetQRCode.getStatus() != 200 || buffer == null || buffer.length < 200) {
			log.error("请求获取小程序码失败, response: {}", Optional.ofNullable(buffer).map(String::new).orElse("response is " +
					"null"));
			throw new ServiceException("请求获取小程序码失败");
		}
		return buffer;
	}
}